package com.ruoyi.common.utils;

import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.exception.CustomException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.codec.Hex;
import org.springframework.security.crypto.codec.Utf8;
import org.springframework.security.crypto.keygen.BytesKeyGenerator;
import org.springframework.security.crypto.keygen.KeyGenerators;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * 安全服务工具类
 *
 * @author ruoyi
 */
public class SecurityUtils {

    /**
     * 盐值字节数组长度，经过Hex编码后为长度6的十六进制字符串
     */
    private static final int SALT_BYTE_LENGTH = 3;

    private final static BytesKeyGenerator SALT_GENERATOR;

    private final static MessageDigest MD5_MESSAGE_DIGEST;

    private static Log log = LogFactory.getLog(SecurityUtils.class);

    static {
        SALT_GENERATOR = KeyGenerators.secureRandom(SALT_BYTE_LENGTH);
        try {
            MD5_MESSAGE_DIGEST = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            log.error("创建MD5摘要工具失败", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取用户账户
     **/
    public static String getUsername() {
        try {
            return getLoginUser().getUsername();
        } catch (Exception e) {
            throw new CustomException("获取用户账户异常", HttpStatus.UNAUTHORIZED);
        }
    }

    /**
     * 获取用户
     **/
    public static LoginUser getLoginUser() {
        try {
            return (LoginUser) getAuthentication().getPrincipal();
        } catch (Exception e) {
            throw new CustomException("获取用户信息异常", HttpStatus.UNAUTHORIZED);
        }
    }

    /**
     * 获取Authentication
     */
    public static Authentication getAuthentication() {
        return SecurityContextHolder.getContext().getAuthentication();
    }

    /**
     * 生成企业征信中心2.0版本标准的密文密码
     * MD5(用户登录名+明文密码+盐值)
     *
     * @param username 用户登录名
     * @param password 明文密码
     * @return 密文密码
     */
    public static String encryptPassword(String username, String password) {
        return encryptPassword(username, password, getSalt());
    }

    /**
     * 对生成企业征信中心2.0版本标准的密文密码
     *
     * @param username 用户登录名
     * @param password 明文密码
     * @param salt     盐值
     * @return 密文密码
     */
    public static String encryptPassword(String username, String password, String salt) {
        // 加盐后的密码，用户名在前，明文密码在中，盐值在后
        byte[] saltedPassword = Utf8.encode((username + password + salt));
        // 摘要后的密码
        byte[] digestedPassword = MD5_MESSAGE_DIGEST.digest(saltedPassword);
        // 经过Hex编码处理的密文密码
        char[] hexEncodedPassword = Hex.encode(digestedPassword);
        // 密文密码字符串，在前端拼接了盐值
        return salt + new String(hexEncodedPassword);
    }

    /**
     * 判断密码是否相同
     *
     * @param rawPassword     真实密码
     * @param encodedPassword 加密后字符
     * @return 结果
     */
    public static boolean matchesPassword(String rawPassword, String encodedPassword) {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        return passwordEncoder.matches(rawPassword, encodedPassword);
    }

    /**
     * 是否为管理员
     *
     * @param userId 用户ID
     * @return 结果
     */
    public static boolean isAdmin(Long userId) {
        return userId != null && (1L == userId || 15L == userId);
    }

    /**
     * 生成盐值
     *
     * @return 盐值，经过十六进制编码
     */
    private static String getSalt() {
        return new String(org.springframework.security.crypto.codec.Hex.encode(SALT_GENERATOR.generateKey()));
    }

    /**
     * 获取六位推荐码
     * @return 推荐码
     */
    public static String getRecommendCode(){
        return getSalt();
    }

}
